数据容器

数据容器

Python 中的数据容器:一种可以容纳多份数据的数据类型,容纳的每一份数据称之为 1 个元素。每一个元素,可以是任意类型的数据,如字符串、数字、布尔等。

数据容器根据特点的不同,如:是否支持重复元素;是否可以修改;是否有序,等分为 5 类,分别是:

序列的切片操作

序列是指:内容连续、有序,可使用下标索引的一类数据容器

列表、元组、字符串,均可以可以视为序列。

序列支持切片,即:列表、元组、字符串,均支持进行切片操作

切片:从一个序列中,取出一个子序列

语法:序列 [起始下标: 结束下标: 步长]。表示从序列中,从指定位置开始,依次取出元素,到指定位置结束,得到一个新序列:

注意,此操作不会影响序列本身,而是会得到一个新的序列,此外,切片操作是可以连写的,灵活使用的话会非常方便。

具体实践请看后续具体容器的实践代码

一个将容器进行倒序返回的通用操作:[::-1],分析如下:

b = a[i:j:s],表示复制 a[i]a[j-1],以生成新的 list 对象,s 表示步长,可以不写,默认为 1,a[i:j:1] 相当于 a[i:j]

推导式

Python 推导式 | 菜鸟教程

Python 推导式是一种独特的数据处理方式,可以从一个数据容器构建另一个新的数据容器的结构体。可以替代简单的 for 循环操作,使用起来非常方便

Python 支持各种数据结构的推导式:

容器

列表(list) - 有序的可变序列

Python3 列表 | 菜鸟教程

Python 中使用最频繁的数据类型,可有序记录一堆数据,长度可变,且索引对应的元素可更改,且元素可重复。

最多可容纳 (2^63)-1 个元素

列表都可以进行的操作包括索引,切片,加,乘,检查成员。此外,Python 已经内置确定序列的长度以及确定最大和最小的元素的方法。

列表是最常用的 Python 数据类型,它可以作为一个方括号内的逗号分隔值出现。列表的数据项不需要具有相同的类型

甚至可以将一个列表作为元素

但是有的操作要求列表元素都是同一类型,比如 maxminsort

简单实践如下:

print("------------------------------初始化----------------------------------")
# 空列表
list_empty = []
print(list_empty)
# 直接通过方法创建一个
list_empty_1 = list()
print(list_empty_1)

list0 = ["baidu", "alli"]
print(list0)
# 列表中的元素可以是不同的类型
list_now = ['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
print(list_now)
# 列表的元素的类型可以是列表,元组,字典,集合
list_nested = ['a', ['b', 'c', 'd'], ('e', 'f'), {"name": 1, "age": 2}, {3, 4, 5, 6, 7, 8}, 9]
print(list_nested)
# 输出 <class 'list'>
print(type(list_nested))

print("------------------------------读取元素/子列表----------------------------------")
# 通过索引访问元素,第一个元素下表为0
print(list_now[0])
print(list_now[2])
# 从后向前访问元素,最后一个元素为-1
print(list_now[-1])
print(list_now[-2])
# 嵌套列表
print(list_nested[1][2])

# 截取列表中的元素返回一个新的list
# 包含左边界,不包含右边界
print(list_now[1:2])
print(list_now[1:-2])
# 指定步长为2
# 结果的索引从0开始,然后是2,然后是4,以此类推
print("步长为2", list_now[::2])
# 左右边界可以不写,
# 左边界不写默认从第一个元素开始
print(list_now[1:])
# 右边界不写默认到最后一个元素
print(list_now[:-2])
# 左右都不写,那就是整个列表
print(list_now[:])
# 当步长大于0的时候左边界必须小于右边界,否则输出空列表
# 输出不为空
print(list_now[-2:-1])
# 输出为空
print(list_now[-1:-2])
# 当步长小于0的时候左边界必须大于右边界,否则输出空列表
# 输出不为空
print(list_now[3:1:-1])
# 输出为空
print(list_now[1:3:-1])

# 列表的倒序操作,跟reverse方法一样
print(list_now)
print-1]

# 注意,对截取出来的列表的更新不会影响原来的列表
sub_list = list_now[0:3]
sub_list[1] = "aaaaa"
print(sub_list)
print(list_now)
# 如果元素是对象或者列表,而对对象属或者列表性进行更新,是会同步到原来的列表中的
list_nested_new = list_nested[0:3]
list_nested_new[1][1] = "&&&&&&"
print(list_nested_new)
print(list_nested)

# 切片操作是可以连写的,灵活使用的话会非常方便
print-1][2:]

print("------------------------------列表元素的增删改查----------------------------------")
# 添加元素
list_now.append(45.12)
print(list_now)

# 在指定位置添加元素
list_now.insert(1, '&&')
print(list_now)

# 直接在列表的末尾追加另一个列表
list_append = ["**", "/", "^^"]
list_now.extend(list_append)
print(list_now)

# extend 可以接受其他的数据容器,比如元组,集合,字典
list_now.extend(("111", "222", "333"))
print(list_now)
# 会将字典的key添加到列表中
list_now.extend({"a1": "111", "b2": "222", "c2": "333"})
print(list_now)
list_now.extend({"qq", "ee", "ff"})
print(list_now)

# 设置指定位置的元素
list_now[1] = "ab"
print(list_now)

# 获取指定元素的下标
print(list_now.index(45.12))
# 如果元素在列表中不存在,会报错
# ValueError: 100 is not in list_now
# print(list_now.index(100))

# 删除第一个匹配的元素
list_now.remove(45.12)
print(list_now)
# 如果元素不存在, remove方法会报错
# ValueError: list_now.remove(x): x not in list_now
# list_now.remove(45.12)
# print(list_now)

# 删除最后一个元素并返回
print(list_now.pop())
print(list_now)
# 也可以指定索引删除元素并返回,类似于remove
print(list_now.pop(-2))
print(list_now)

# 也可以用 del 命令删除指定索引的元素
del list_now[-1]
print(list_now)

# 统计某个元素在列表中出现的次数,比如 9 这个元素
print(list_now.count(9))

print("------------------------------对列表的整体操作----------------------------------")
# 列表长度
print(len(list_now))

list_int = [12, 45, 78]
print(max(list_int))
print(min(list_int))
# max 和 min 只能对所有元素类型相同的list进行运算,sort方法也是,否则会报错

# 列表的复制
# 浅复制,不是深复制
list_copy = list_now.copy()
print(list_copy)
# 对复制出来的列表的指定索引的更新,不会同步到原来的列表
list_copy[0] = 999
print(list_copy)
print(list_now)
# 如果元素是对象或者列表,而对对象属性或者列表进行更新,是会同步到原列表中的
list_nested_copy = list_nested.copy()
list_nested_copy[1][1] = "******"
print(list_nested_copy)
print(list_nested)

# 将list倒序,也可以直接通过 [::-1] 实现
list_now.reverse()
print(list_now)
list_now.reverse()

# 清除列表中的所有元素
list_now.clear()
print(list_now)

print("------------------------------列表元素的排序----------------------------------")
# sort 只能对所有元素类型相同的list进行运算,max 和 min 方法也是,否则会报错
# 对列表中的元素进行排序
list_num = [12.12, 78, 1, 5, 6, 3]
print(list_num)
# 默认升序
list_num.sort()
print(list_num)
# 倒叙
list_num.sort(reverse=True)
print(list_num)


# 自定义排序规则
# 根据元素长度
def eleLen(elem):
    # 相当于一个hash操作
    # 返回值越大,升序排序的时候就越靠后
    if type(elem) == bool:
        return 1
    elif type(elem) == int:
        return len(str(elem))
    else:
        # 剩下的都是容器了
        return len(elem)


str_list = ['aaaaaa', 'aa', 'aaa', 'aaaaaaaaaaaaaaa', 'aaaaaaaaa']
str_list.sort(key=eleLen, reverse=False)
print(str_list)

# 容器通用排序操作,返回一个新的列表,原字典是不变的,
# list中的元素的类型是不限定的,因此得定制key函数,否则无法比较,只能返回空列表
sorted_list = sorted(list_copy, key=eleLen, reverse=False)
print(list_copy)
print(sorted_list)

print("------------------------------对列表的符号操作,非常方便----------------------------------")
list_new = ["aaa", "bbb", "ccc", "ddd"]
list_2_plus = ["1111", "222", "333", "444", "555"]
# 可以直接通过 + 将两个列表合并,类似于 extend 方法
plus = list_new + list_2_plus
print(plus)
# 原列表不会受影响
print(list_new)

# 通过 *n 将列表的元素复制n倍
multiple = list_new * 4
print(multiple)
# 原列表不会受影响
print(list_new)

# 直接通过 in 语句判断元素是否在列表中,类似于 index 方法
print(3 in list_new)
print("aaa" in list_new)
# not in 判断元素是否不在列表中
print("aaa" not in list_new)

# for-in 循环遍历list
for i in list_new:
    print(i, end=' ')
print()
print(list_new)

print("------------------------------列表推导式----------------------------------")

list_exp = [x + 2 for x in range(0, 10) if x < 6]
# 输出 [2, 3, 4, 5, 6, 7]
print(list_exp)

print("------------------------------列表的比较----------------------------------")

# 导入 operator 模块
import operator

a = [1, 2]
b = [2, 3]
c = [2, 3]
print("operator.eq(a,b): ", operator.eq(a, b))
print("operator.eq(c,b): ", operator.eq(c, b))

# 复杂列表
str_list_0 = ['aaa', 'bb', 'cccccc', 'dd']
str_list_0_copy = ['aaa', 'bb', 'cccccc', 'dd']
str_list_1 = ['aaa', 'cccccc', 'dd', 'bb']
print(operator.eq(str_list_0, str_list_0_copy))
print(operator.eq(str_list_0, str_list_1))
# 元素类型为列表的列表
list_ele_list_0 = [['aaa'], ['111'], ['222']]
list_ele_list_1 = list_ele_list_0.copy()
print(list_ele_list_1)
print(operator.eq(list_ele_list_0, list_ele_list_1))

print("------------------------------将别的容器对象转化为列表----------------------------------")
# 从字符串转化而来
list_from_str = list("abcdefghijklmnopqrstuvwxyz")
print(list_from_str)
# 从元组转化而来
list_from_tuple = list((12, 23.45))
print(list_from_tuple)
# 从集合转化而来
list_from_set = list({12, 23.45})
print(list_from_set)
# 从字典转换而来 获取key转化为列表
list_from_dict = list({"name": "12", "age": "23.45"})
print(list_from_dict)

输出:

------------------------------初始化----------------------------------
[]
[]
['baidu', 'alli']
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
['a', ['b', 'c', 'd'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9]
<class 'list'>
------------------------------读取元素/子列表----------------------------------
a
c
False
True
d
['b']
['b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9]
步长为2 ['a', 'c', 'e', 1, 3, 5, 7, 9, False]
['b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9]
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
[True]
[]
['d', 'c']
[]
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
[False, True, 9, 8, 7, 6, 5, 4, 3, 2, 1, 'f', 'e', 'd', 'c', 'b', 'a']
['a', 'aaaaa', 'c']
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
['a', ['b', '&&&&&&', 'd'], ('e', 'f')]
['a', ['b', '&&&&&&', 'd'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9]
['d', 'c', 'b', 'a']
------------------------------列表元素的增删改查----------------------------------
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12]
['a', '&&', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12]
['a', '&&', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12, '**', '/', '^^']
['a', '&&', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12, '**', '/', '^^', '111', '222', '333']
['a', '&&', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2']
['a', '&&', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2', 'ff', 'qq', 'ee']
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 45.12, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2', 'ff', 'qq', 'ee']
18
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2', 'ff', 'qq', 'ee']
ee
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2', 'ff', 'qq']
ff
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2', 'qq']
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2']
1
------------------------------对列表的整体操作----------------------------------
27
78
12
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2']
[999, 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2']
['a', 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2']
['a', ['b', '******', 'd'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9]
['a', ['b', '******', 'd'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9]
['c2', 'b2', 'a1', '333', '222', '111', '^^', '/', '**', False, True, 9, 8, 7, 6, 5, 4, 3, 2, 1, 'f', 'e', 'd', 'c', 'b', 'ab', 'a']
[]
------------------------------列表元素的排序----------------------------------
[12.12, 78, 1, 5, 6, 3]
[1, 3, 5, 6, 12.12, 78]
[78, 12.12, 6, 5, 3, 1]
['aa', 'aaa', 'aaaaaa', 'aaaaaaaaa', 'aaaaaaaaaaaaaaa']
[999, 'ab', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '**', '/', '^^', '111', '222', '333', 'a1', 'b2', 'c2']
['b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, '/', 'ab', '**', '^^', 'a1', 'b2', 'c2', 999, '111', '222', '333']
------------------------------对列表的符号操作,非常方便----------------------------------
['aaa', 'bbb', 'ccc', 'ddd', '1111', '222', '333', '444', '555']
['aaa', 'bbb', 'ccc', 'ddd']
['aaa', 'bbb', 'ccc', 'ddd', 'aaa', 'bbb', 'ccc', 'ddd', 'aaa', 'bbb', 'ccc', 'ddd', 'aaa', 'bbb', 'ccc', 'ddd']
['aaa', 'bbb', 'ccc', 'ddd']
False
True
False
aaa bbb ccc ddd 
['aaa', 'bbb', 'ccc', 'ddd']
------------------------------列表推导式----------------------------------
[2, 3, 4, 5, 6, 7]
------------------------------列表的比较----------------------------------
operator.eq(a,b):  False
operator.eq(c,b):  True
True
False
[['aaa'], ['111'], ['222']]
True
------------------------------将别的容器对象转化为列表----------------------------------
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
[12, 23.45]
[12, 23.45]
['name', 'age']

Process finished with exit code 0

元组(tuple) - 有序的不可变序列

Python3 元组 | 菜鸟教程

Python 的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号 ( ),列表使用方括号 [ ]。

元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。

元组类型的变量一旦初始化,就动都不能动了,不能增加元素,不能更新指定索引的元素,不能删除元素,但是如果元组的元素的类型是列表或者其他可变对象,那我们是可以修改这个(元素)对象的属性

这个就跟 Java 中 final 关键字的效果很类似

其实所谓元组的不可变指的是元组所指向的内存中的内容不可变。如果是列表或者其他对象,保存在元组中的只是列表的指针,元组或者对象的数据保存在另外的内存空间中

在某些场景下,tuple 适合定义一些固定常量,比如字典数据

简单实践如下:

print("------------------------------初始化----------------------------------")
# 空元组
tuple0 = ()
print(tuple0, type(tuple0))
# 直接通过方法创建一个
tuple1 = tuple()
print(tuple1, type(tuple1))

# 只有一个元素的时候,在这个元素后面要加上一个逗号,不加的话整体不会被识别为元组,而是运算符
tuple_single = (50)
# 50 <class 'int'>
print(tuple_single, type(tuple_single))
# 下面这样才是元组
tuple_single_new = (50,)
# (50,) <class 'tuple'>
print(tuple_single_new, type(tuple_single_new))

tuple3 = ("baidu", "alli")
print(tuple3)
# 元组中的元素可以是不同的类型
tuple_now = ('a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
print(tuple_now)
# 元组的元素的类型可以是列表,元组,字典,集合
tuple_nested = ('a', ['b', 'c', 'd'], ('e', 'f'), {"name": 1, "age": 2}, {3, 4, 5, 6, 7, 8}, 9)
print(tuple_nested)
# 输出 <class 'tuple'>
print(type(tuple_nested))

# 元组声明的时候,可以把括号去掉,这一点很重要,当我们看到用一个变量等于逗号分割开的一系列元素的时候,这个变量其实是元组
tuple_simple = 'a', 'b', 'c', 1, 2, 3, False,
print(tuple_simple)
# 单个元素的元组元素末尾得加上一个逗号
tuple_simplest = 12,
# (12,) <class 'tuple'>
print(tuple_simplest, type(tuple_simplest))

print("------------------------------读取元素/子元组----------------------------------")
# 通过索引访问元素,第一个元素下表为0
print(tuple_now[0])
print(tuple_now[2])
# 从后向前访问元素,最后一个元素为-1
print(tuple_now[-1])
print(tuple_now[-2])
# 嵌套元组
print(tuple_nested[2][1])

# 截取元组中的元素返回一个新的tuple
# 包含左边界,不包含右边界
print(tuple_now[1:2])
print(tuple_now[1:-2])
# 指定步长为2
# 结果的索引从0开始,然后是2,然后是4,以此类推
print("步长为2", tuple_now[::2])
# 左右边界可以不写,
# 左边界不写默认从第一个元素开始
print(tuple_now[1:])
# 右边界不写默认到最后一个元素
print(tuple_now[:-2])
# 左右都不写,那就是整个元组
print(tuple_now[:])
# 当步长大于0的时候左边界必须小于右边界,否则输出空元组
# 输出不为空
print(tuple_now[-2:-1])
# 输出为空
print(tuple_now[-1:-2])
# 当步长小于0的时候左边界必须大于右边界,否则输出空元组
# 输出不为空
print(tuple_now[3:1:-1])
# 输出为空
print(tuple_now[1:3:-1])

# 元组的倒序操作
print(tuple_now)
# 返回一个新的倒叙的元组
print-1]

# 切片操作是可以连写的,灵活使用的话会非常方便
print-1][2:]

print("------------------------------元组元素的增删改查----------------------------------")

# tuple_now[1] = "aaaaa"
# # 报错,元组中的指定索引的元素不允许更新
# # 'tuple' object does not support item assignment
# print(tuple_now)
# 同时也不允许增加元素
# 同时也不允许删除元组中的元素,也就是说整个元组一旦初始化,就动都不能动了
# 但是有一个特例,就是如果元组的元素的类型是列表或者其他对象,那我们是可以修改对象的属性的
# 这就有点像Java中final关键字的效果

print(tuple_nested)
tuple_nested[1][0] = "+"
tuple_nested[1][1] = "-"
tuple_nested[1][2] = "&&"
print(tuple_nested)

# 但是依然不能修改类型为元组类型的元素
# tuple_nested[2][1] = "***"

# 但是我们可以删除整个元组
tuple_del = 12, 45, 78
print(tuple_del)
del tuple_del
# name 'tuple_del' is not defined.
# print(tuple_del)

# 获取指定元素的下标
print(tuple_now.index(9))
# 如果元素在元组中不存在,会报错
# ValueError: 100 is not in tuple_now
# print(tuple_now.index(100))

# 统计某个元素在元组中出现的次数,比如 1 这个元素
# 返回2 因为True也算1
print(tuple_now.count(1))
# 返回1 因为False也算0
print(tuple_now.count(0))

print("------------------------------对元组的整体操作----------------------------------")
# 元组长度
print(len(tuple_now))

tuple_int = (12, 45, 78, 754)
print(max(tuple_int))
print(min(tuple_int))

# max 和 min 只能对所有元素类型相同的tuple进行运算,否则会报错
# tuple_mix = (12, 45, 78, 754,"sdfasd")
# # '>' not supported between instances of 'str' and 'int'
# print(max(tuple_mix))

print("------------------------------元组元素的排序----------------------------------")


# 自定义排序规则
# 根据元素长度
def eleLen(elem):
    # 相当于一个hash操作
    # 返回值越大,升序排序的时候就越靠后
    if type(elem) == bool:
        return 1
    elif type(elem) == int:
        return len(str(elem))
    else:
        # 剩下的都是容器了
        return len(elem)


# 容器通用排序操作,返回一个新的列表,原元组是不变的,
# 元组中的元素的类型是不限定的,因此得定制key函数,否则无法比较,只能返回空列表
sorted_list = sorted(tuple_now, key=eleLen, reverse=False)
print(tuple_now)
print(sorted_list)


print("------------------------------对元组的符号操作,非常方便----------------------------------")
tuple_new = ("aaa", "bbb", "ccc", "ddd")
tuple_2_plus = ("1111", "222", "333", "444", "555")
# 可以直接通过 + 将两个元组合并
plus = tuple_new + tuple_2_plus
print(plus)
# 原元组不会受影响
print(tuple_new)

# 通过 *n 将元组的元素复制n倍
multiple = tuple_new * 4
print(multiple)
# 原元组不会受影响
print(tuple_new)

# 直接通过 in 语句判断元素是否在元组中,类似于 index 方法
print(3 in tuple_new)
print("aaa" in tuple_new)
# not in 判断元素是否不在元组中
print("aaa" not in tuple_new)

# for-in 循环遍历tuple
for i in tuple_new:
    print(i, end=' ')
print()
print(tuple_new)

print("------------------------------元组推导式----------------------------------")

tuple_exp_generator = (x + 2 for x in range(0, 10) if x < 6)
tuple_exp = tuple(tuple_exp_generator)
# 输出 (2, 3, 4, 5, 6, 7)
print(tuple_exp)

print("------------------------------元组的比较----------------------------------")

# 导入 operator 模块
import operator

a = (1, 2)
b = (2, 3)
c = (2, 3)
print("operator.eq(a,b): ", operator.eq(a, b))
print("operator.eq(c,b): ", operator.eq(c, b))

# 复杂元组
str_tuple_0 = ('aaa', 'bb', 'cccccc', 'dd')
str_tuple_0_copy = ('aaa', 'bb', 'cccccc', 'dd')
str_tuple_1 = ('aaa', 'cccccc', 'dd', 'bb')
print(operator.eq(str_tuple_0, str_tuple_0_copy))
print(operator.eq(str_tuple_0, str_tuple_1))
# 元素类型为元组的元组
tuple_ele_tuple_0 = (('aaa'), ('111'), ('222'))
tuple_ele_tuple_1 = (('aaa'), ('111'), ('222'))
print(operator.eq(tuple_ele_tuple_0, tuple_ele_tuple_1))

print("------------------------------将别的容器对象转化为元组----------------------------------")
# 从字符串转化而来
tuple_from_str = tuple("abcdefghijklmnopqrstuvwxyz")
print(tuple_from_str)
# 从元组转化而来
tuple_from_list = tuple([12, 23.45])
print(tuple_from_list)
# 从集合转化而来
tuple_from_set = tuple({12, 23.45})
print(tuple_from_set)
# 从字典转换而来 获取key转化为元组
tuple_from_dict = tuple({"name": "12", "age": "23.45"})
print(tuple_from_dict)

输出日志:

------------------------------初始化----------------------------------
() <class 'tuple'>
() <class 'tuple'>
50 <class 'int'>
(50,) <class 'tuple'>
('baidu', 'alli')
('a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
('a', ['b', 'c', 'd'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9)
<class 'tuple'>
('a', 'b', 'c', 1, 2, 3, False)
(12,) <class 'tuple'>
------------------------------读取元素/子元组----------------------------------
a
c
False
True
f
('b',)
('b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9)
步长为2 ('a', 'c', 'e', 1, 3, 5, 7, 9, False)
('b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
('a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9)
('a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
(True,)
()
('d', 'c')
()
('a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
(False, True, 9, 8, 7, 6, 5, 4, 3, 2, 1, 'f', 'e', 'd', 'c', 'b', 'a')
('d', 'c', 'b', 'a')
------------------------------元组元素的增删改查----------------------------------
('a', ['b', 'c', 'd'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9)
('a', ['+', '-', '&&'], ('e', 'f'), {'name': 1, 'age': 2}, {3, 4, 5, 6, 7, 8}, 9)
(12, 45, 78)
14
2
1
------------------------------对元组的整体操作----------------------------------
17
754
12
------------------------------元组元素的排序----------------------------------
('a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False]
------------------------------对元组的符号操作,非常方便----------------------------------
('aaa', 'bbb', 'ccc', 'ddd', '1111', '222', '333', '444', '555')
('aaa', 'bbb', 'ccc', 'ddd')
('aaa', 'bbb', 'ccc', 'ddd', 'aaa', 'bbb', 'ccc', 'ddd', 'aaa', 'bbb', 'ccc', 'ddd', 'aaa', 'bbb', 'ccc', 'ddd')
('aaa', 'bbb', 'ccc', 'ddd')
False
True
False
aaa bbb ccc ddd 
('aaa', 'bbb', 'ccc', 'ddd')
------------------------------元组推导式----------------------------------
(2, 3, 4, 5, 6, 7)
------------------------------元组的比较----------------------------------
operator.eq(a,b):  False
operator.eq(c,b):  True
True
False
True
------------------------------将别的容器对象转化为元组----------------------------------
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')
(12, 23.45)
(12, 23.45)
('name', 'age')

Process finished with exit code 0

字符串(str) - 字符序列

字符串的基本操作,请看《基本语法.md》的 字符串 小节

字符串是字符的容器,一个字符串可以存放任意数量的字符。

和其它容器如:列表、元组一样,字符串也可以通过下标进行访问,同元组一样,字符串是一个无法修改的数据容器

简单实践如下:

print("------------------------------初始化----------------------------------")
# 直接通过方法创建一个
str_empty = str()
print(str_empty, type(str_empty))

str_now = "abcdefg123456"

print("------------------------------读取字符串中的子字符/子字符串----------------------------------")

# 通过索引访问字符,第一个字符下表为0
print(str_now[0])
print(str_now[2])
# 从后向前访问字符,最后一个字符为-1
print(str_now[-1])
print(str_now[-2])

# 截取字符串中的字符返回一个新的str
# 包含左边界,不包含右边界
print(str_now[1:2])
print(str_now[1:-2])
# 指定步长为2
# 结果的索引从0开始,然后是2,然后是4,以此类推
print("步长为2", str_now[::2])
# 左右边界可以不写,
# 左边界不写默认从第一个字符开始
print(str_now[1:])
# 右边界不写默认到最后一个字符
print(str_now[:-2])
# 左右都不写,那就是整个字符串
print(str_now[:])
# 当步长大于0的时候左边界必须小于右边界,否则输出空字符串
# 输出不为空
print(str_now[-2:-1])
# 输出为空
print(str_now[-1:-2])
# 当步长小于0的时候左边界必须大于右边界,否则输出空字符串
# 输出不为空
print(str_now[3:1:-1])
# 输出为空
print(str_now[1:3:-1])

sub_str = str_now[0:3]
# 无法直接更新指定索引的字符
# 'str' object does not support item assignment
# sub_str[1] = "$"

# 字符串的倒序操作
print(str_now)
print-1]

# 切片操作是可以连写的,灵活使用的话会非常方便
print-1][2:]

print("------------------------------字符串元素的增删改查----------------------------------")

str_2_del = "i am dying"
print(str_2_del)
# 可以通过del删除字符串
del str_2_del
# print(str_2_del)

# 具体请看 str_function.py 中的实践
# 查询指定字符串在特定范围内第一次出现的位置
print(str_now.index("abc"))
# 在指定的范围内查找特定字符串出现的次数
print(str_now.count("123"))

print("------------------------------对字符串的整体操作----------------------------------")
# 字符串长度
print(len(str_now))

str_compare = "我的123456789abcdefg"
# 这里比较的好像是unicode的码点
print(max(str_compare))
# 字符串中的最大值
print(min(str_compare))

print("------------------------------字符串中的字符的排序----------------------------------")

# 容器通用排序操作,返回一个新的列表,原字符串是不变的,
# 字符串中的字符类型是str,所以不用考虑多种类型的情况
sorted_list = sorted(str_now, reverse=False)
print(str_now)
print(sorted_list)

print("------------------------------对字符串的符号操作,非常方便----------------------------------")
str_new = "aaa-bbb-ccc-ddd"
str_2_plus = "1111-222-333-444-555"
# 可以直接通过 + 将两个字符串合并
plus = str_new + str_2_plus
print(plus)
# 原字符串不会受影响
print(str_new)

# 通过 *n 将字符串复制n倍
multiple = str_new * 4
print(multiple)
# 原字符串不会受影响
print(str_new)

# 直接通过 in 语句判断元素是否在字符串中,类似于 index 方法
print("-" in str_new)
print("aaa" in str_new)
# not in 判断元素是否不在字符串中
print("aaa" not in str_new)

# for-in 循环遍历tuple
for i in str_new:
    print(i, end=' ')
print()
print(str_new)

print("------------------------------字符串的比较----------------------------------")

# 导入 operator 模块
import operator

a = "12"
b = "23"
c = "23"
print("operator.eq(a,b): ", operator.eq(a, b))
print("operator.eq(c,b): ", operator.eq(c, b))

# 复杂字符串
str_str_0 = 'aaa-bb-cccccc-dd'
str_str_0_copy = 'aaa-bb-cccccc-dd'
str_str_1 = 'aaa-cccccc-dd-bb'
print(operator.eq(str_str_0, str_str_0_copy))
print(operator.eq(str_str_0, str_str_1))

print("------------------------------将别的容器对象转化为字符串----------------------------------")
# 从列表转化而来
str_from_list = str([12, 23.45])
# 输出  "[12, 23.45]"
print(str_from_list)
# 从元组转化而来
str_from_tuple = str((12, 23.45))
# 输出 "(12, 23.45)"
print(str_from_tuple)
# 从集合转化而来
str_from_set = str({12, 23.45})
# 输出 "{12, 23.45}"
print(str_from_set)
# 从字典转化而来
str_from_dict = str({"name": "12", "age": "23.45"})
# 输出 "{'name': '12', 'age': '23.45'}"
print(str_from_dict)

输出:

------------------------------初始化----------------------------------
 <class 'str'>
------------------------------读取字符串中的子字符/子字符串----------------------------------
a
c
6
5
b
bcdefg1234
步长为2 aceg246
bcdefg123456
abcdefg1234
abcdefg123456
5

dc

abcdefg123456
654321gfedcba
dcba
------------------------------字符串元素的增删改查----------------------------------
i am dying
0
1
------------------------------对字符串的整体操作----------------------------------
13
的
1
------------------------------字符串中的字符的排序----------------------------------
abcdefg123456
['1', '2', '3', '4', '5', '6', 'a', 'b', 'c', 'd', 'e', 'f', 'g']
------------------------------对字符串的符号操作,非常方便----------------------------------
aaa-bbb-ccc-ddd1111-222-333-444-555
aaa-bbb-ccc-ddd
aaa-bbb-ccc-dddaaa-bbb-ccc-dddaaa-bbb-ccc-dddaaa-bbb-ccc-ddd
aaa-bbb-ccc-ddd
True
True
False
a a a - b b b - c c c - d d d 
aaa-bbb-ccc-ddd
------------------------------字符串的比较----------------------------------
operator.eq(a,b):  False
operator.eq(c,b):  True
True
False
------------------------------将别的容器对象转化为字符串----------------------------------
[12, 23.45]
(12, 23.45)
{12, 23.45}
{'name': '12', 'age': '23.45'}

Process finished with exit code 0

集合(set) - 无序的不重复元素容器

集合不是序列

Python3 集合 | 菜鸟教程

集合(set)是一个无序的不重复元素容器()。自带去重功能,同时因为集合是无序,所以不支持下标索引访问(subscriptable

可以使用大括号 {} 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 {},因为 {} 是用来创建一个空字典。

集合的元素的类型可以是元组,但是不能是列表,字典,集合。

如果元组的元素的顺序不一样,也会被视为不同的元素保留在集合中

简单实践如下:

print("------------------------------初始化----------------------------------")

# 空集合
set_empty = {}
# 输出{} <class 'dict'>,字典类型,而不是集合类型
print(set_empty, type(set_empty))
# 这样才是空集合
set_empty = set()
# 输出set() <class 'set'>
print(set_empty, type(set_empty))

set_example = {"a", "a", "a", "a", "a", "a"}
# 只会输出 {'a'},说明其自动去充了
print(set_example)
set_example_2 = set(["b", "b", "b", "b", "b", "b"])
# 只会输出 {'b'},说明set方法将列表中的元素自动去重了
print(set_example_2)

# 集合中的元素可以是不同的类型
set_now = {'a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5, 6, 7, 8, 9, True, False}
# set 是一个无序的集合,不会按照元素声明的顺序保存元素
print(set_now)
# 集合的元素的类型可以是元组,但是不能是列表,字典,集合
# 如果元组的元素的顺序不一样,也会被视为不同的元素保留在集合中
set_nested = {'a', ('e', 'f'), ('f', 'e'), 9, 10}
# 输出 {('e', 'f'), 9, 10, 'a', ('f', 'e')}
print(set_nested)
# 输出 <class 'set'>
print(type(set_nested))

print("------------------------------读取元素/子集合----------------------------------")
# 报错:TypeError: 'set' object is not subscriptable
# 集合无法通过下标访问
# print(set_now[1])
print("集合无法通过下标访问")

print("------------------------------集合元素的增删改查----------------------------------")
# 添加元素
# add 方法只能添加一个元素,如果元素已经存在了,则啥也不干,不存在,则添加到集合中
set_now.add(1)
print(set_now)
set_now.add(10)
print(set_now)
# add 方法传入一个元组,不会出现元组中的元素跟集合中现有元素取并集的效果,而是直接将元组整体作为一个元素添加到集合中,想要实现这样的效果应该使用update方法
# add 方法无法添加列表、字典、集合作为集合中的元素,这个在前面初始化集合的时候就已经学习过了
set_now.add((1, 2))
print(set_now)
# update方法可传入多个容器对象(可传入多个参数),然后会自动将这些容器对象中的元素与集合中的元素进行取并集的操作(效果等同于 | 操作符和 union 方法)
# 字典会使用key,不使用value
# 很明显,update方法更加方便实用
set_now.update(["aa", "bb", "cc"], (1, 2, 3, 11, 12), {"a1", "b1", "c1"}, {"A1": 94, "B1": 98, "C1": 99})
print(set_now)

# 删除匹配的元素
set_now.remove(12)
print(set_now)
# 删除元组
set_now.remove((1, 2))
print(set_now)
# 如果元素不存在, remove方法会报错
# KeyError: 112
# set_now.remove(112)
# print(set_now)

# 移除匹配的元素,如果这个元素不在集合中,那就啥也不做
# 很明显,discard 更好用
set_now.discard(112)

# 随机删除集合中的一个元素,如果集合是空的,那就会报错
# pop 方法会对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除。
print(set_now.pop())
print(set_now)

print("------------------------------对集合的整体操作----------------------------------")
# 集合长度
print(len(set_now))

set_int = [12, 45, 78]
print(max(set_int))
print(min(set_int))
# max 和 min 只能对所有元素类型相同的set进行运算,否则会报错

# 集合的复制
# 浅复制,不是深复制
# 如果元素是对象或者集合,而对对象属性或者集合进行更新,是会同步到原集合中的
set_copy = set_now.copy()
print("原始set", set_now)
print("复制set", set_copy)

# 清除集合中的所有元素
set_now.clear()
print(set_now)

print("------------------------------集合元素的排序----------------------------------")


# 自定义排序规则
# 根据元素长度
def eleLen(elem):
    # 相当于一个hash操作
    # 返回值越大,升序排序的时候就越靠后
    if type(elem) == bool:
        return 1
    elif type(elem) == int:
        return len(str(elem))
    else:
        # 剩下的都是容器了
        return len(elem)


# 容器通用排序操作,返回一个新的列表,原字典是不变的,
# 集合中的元素的类型是不限定的,因此得定制key函数,否则无法比较,只能返回空列表
sorted_list = sorted(set_copy, key=eleLen, reverse=False)
print(set_copy)
print(sorted_list)

print("------------------------------对集合的符号操作,非常方便----------------------------------")
# 集合不支持 + 操作
# 集合不支持 * 操作

# 注意,以下操作符都不会修改原集合,而是返回一个新的集合
# a - b  集合a中包含而集合b中不包含的元素,类似于 difference 方法
# a | b  集合a或b中包含的所有元素,类似于 union 方法
# a & b  集合a和b中都包含了的元素,类似于 intersection 方法
# a ^ b  不同时包含于a和b的元素,类似于 symmetric_difference 方法

set_1 = {"aaa", "bbb", "ccc", "ddd", "1111", "222"}
set_2 = {"1111", "222", "333", "444", "555"}
# set_1 中删除 set_2 中的元素
print(set_1 - set_2)
# set_1 set_2 取并集
print(set_1 | set_2)
# set_1 set_2 取交集
print(set_1 & set_2)
# set_1 set_2 的并集去掉 set_1 set_2 的交集
print(set_1 ^ set_2)
# 等于
print((set_1 | set_2) - (set_1 & set_2))
# 可以通过 - 快速地去除一个元素
print(set_1 - {"aaa"})

# 直接通过 in 语句判断元素是否在集合中,类似于 index 方法
print(3 in set_1)
print("aaa" in set_1)
# not in 判断元素是否不在集合中
print("aaa" not in set_1)

# for-in 循环遍历set
# 乱序输出
for i in set_1:
    print(i, end=' ')
print()
print(set_1)

print("------------------------------集合推导式操作----------------------------------")
set_exp = {x for x in 'abracadabra' if x not in 'abc'}
print(set_exp)

print("------------------------------集合的比较----------------------------------")

# 导入 operator 模块
import operator

a = {1, 2}
b = {2, 1}
c = (2, 3)
# True
print("operator.eq(a,b): ", operator.eq(a, b))
# False
print("operator.eq(c,b): ", operator.eq(c, b))

print("------------------------------集合的相关方法----------------------------------")

set_3 = {"a1", "b1", "c1"}
set_4 = {"a1", "a2", "a3"}
set_5 = {"1", "2", "3"}
set_6 = {"1", "2"}
set_7 = {"2", "3", "4", "5"}

# 取并集,效果等同于 | 操作符
print(set_3.union(set_4))

# 集合关系的判断
# 两个集合是否没有交集
print(set_3.isdisjoint(set_4))
print(set_3.isdisjoint(set_5))
# 当前集合是否是传入的集合的子集
print(set_6.issubset(set_5))
# 当前集合是否是传入的集合的父集
print(set_5.issuperset(set_6))

# 在当前集合中,但是不在传入的集合中的,可传入多个集合,类似 - 操作符
# 但是返回的是一个新的集合,原集合是不受影响的
print(set_5.difference(set_6))
print(set_5)
# 原集合会受影响,要谨慎使用
# 此方法返回None
print(set_5.difference_update(set_6))
print(set_5)

# 取交集,类似 & 操作符
print(set_3.intersection(set_4))
set_3.intersection_update(set_4)
print(set_3)

# 返回两个集合中所有只存在于一个集合中的元素,类似 ^ 操作符
print(set_6.symmetric_difference(set_7))
set_6.symmetric_difference_update(set_7)
print(set_6)

print("------------------------------将别的容器对象转化为集合----------------------------------")
# 从字符串转化而来
set_from_str = set("abcdefghijklmnopqrstuvwxyz")
print(set_from_str)
# 从列表转化而来
set_from_list = set([12, 23.45])
print(set_from_list)
# 从元组转化而来
set_from_tuple = set((12, 23.45))
print(set_from_tuple)
# 从字典转换而来 获取key转化为列表
set_from_dict = set({"name": "12", "age": "23.45"})
print(set_from_dict)

输出:

------------------------------初始化----------------------------------
{} <class 'dict'>
set() <class 'set'>
{'a'}
{'b'}
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 'a', 'c', 'd', 'b', 'e'}
{('e', 'f'), ('f', 'e'), 9, 10, 'a'}
<class 'set'>
------------------------------读取元素/子集合----------------------------------
集合无法通过下标访问
------------------------------集合元素的增删改查----------------------------------
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 'a', 'c', 'd', 'b', 'e'}
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, 'a', 'c', 'd', 'b', 'e'}
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, (1, 2), 'a', 'c', 'd', 'b', 'e'}
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, (1, 2), 11, 12, 'b1', 'A1', 'cc', 'C1', 'a', 'c1', 'a1', 'c', 'd', 'b', 'bb', 'B1', 'e', 'aa'}
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, (1, 2), 11, 'b1', 'A1', 'cc', 'C1', 'a', 'c1', 'a1', 'c', 'd', 'b', 'bb', 'B1', 'e', 'aa'}
{False, 1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, 11, 'b1', 'A1', 'cc', 'C1', 'a', 'c1', 'a1', 'c', 'd', 'b', 'bb', 'B1', 'e', 'aa'}
False
{1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, 11, 'b1', 'A1', 'cc', 'C1', 'a', 'c1', 'a1', 'c', 'd', 'b', 'bb', 'B1', 'e', 'aa'}
------------------------------对集合的整体操作----------------------------------
26
78
12
原始set {1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, 11, 'b1', 'A1', 'cc', 'C1', 'a', 'c1', 'a1', 'c', 'd', 'b', 'bb', 'B1', 'e', 'aa'}
复制set {1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, 11, 'b1', 'a1', 'A1', 'cc', 'C1', 'a', 'c', 'd', 'b', 'bb', 'aa', 'B1', 'e', 'c1'}
set()
------------------------------集合元素的排序----------------------------------
{1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 10, 11, 'b1', 'a1', 'A1', 'cc', 'C1', 'a', 'c', 'd', 'b', 'bb', 'aa', 'B1', 'e', 'c1'}
[1, 2, 3, 4, 5, 6, 7, 'f', 8, 9, 'a', 'c', 'd', 'b', 'e', 10, 11, 'b1', 'a1', 'A1', 'cc', 'C1', 'bb', 'aa', 'B1', 'c1']
------------------------------对集合的符号操作,非常方便----------------------------------
{'ccc', 'bbb', 'ddd', 'aaa'}
{'ddd', 'aaa', '444', 'bbb', '1111', '333', 'ccc', '222', '555'}
{'222', '1111'}
{'ddd', '333', 'ccc', '555', 'aaa', '444', 'bbb'}
{'ddd', 'aaa', '444', 'bbb', '333', 'ccc', '555'}
{'ddd', '1111', 'bbb', 'ccc', '222'}
False
True
False
ccc 222 ddd aaa bbb 1111 
{'ccc', '222', 'ddd', 'aaa', 'bbb', '1111'}
------------------------------集合推导式操作----------------------------------
{'r', 'd'}
------------------------------集合的比较----------------------------------
operator.eq(a,b):  True
operator.eq(c,b):  False
------------------------------集合的相关方法----------------------------------
{'c1', 'a1', 'b1', 'a2', 'a3'}
False
True
True
True
{'3'}
{'1', '3', '2'}
None
{'3'}
{'a1'}
{'a1'}
{'4', '3', '5', '1'}
{'4', '3', '5', '1'}
------------------------------将别的容器对象转化为集合----------------------------------
{'f', 'k', 'v', 'a', 'c', 'd', 'z', 's', 'n', 'o', 'y', 'q', 'i', 'l', 'x', 'w', 't', 'p', 'h', 'b', 'j', 'g', 'r', 'u', 'e', 'm'}
{12, 23.45}
{12, 23.45}
{'name', 'age'}

Process finished with exit code 0

Python 的集合中自带了取并集,交集,差集的操作,但是 Java 的 JDK 中是不自带的,在 Guava 中对这些功能进行了实现,比如 Sets.intersectionSets.differenceSets.union,API 的名字跟 Python 的都一样。

字典(dict) - 键值对容器

集合不是序列

Python3 字典 | 菜鸟教程

字典是另一种可变容器模型,且可存储任意类型对象。

字典的每个键值 key=>value 对用冒号 : 分割,每个对之间用逗号 (,) 分割,整个字典包括在花括号 {} 中

注意:dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict。

键必须是唯一的,但值则不必。如果 key 重复,则后面的会覆盖前面的

键必须是不可变的,如字符串,数字 , Boolean,此外,元组可以作为 key,因为元组是不可变的,但是列表、集合、字典是可变的,都不能作为 key

值可以取任何数据类型,可以是任何的 python 对象,既可以是标准的对象,也可以是用户定义的,可以是字符串,数字,列表,元组,集合,字典,并且可以继续嵌套下去

字典完美契合 JSON 的格式

字典中的键值对,也是有序的,从 dict.popitem 方法就可以看出,但是字典无法通过下标索引访问,只能通过 key 访问。所以字典只能用 for 循环遍历,无法使用 while 遍历

从 python3.6 开始,dict 的插入变为有序,即字典整体变的有序;而之前的版本,比如 python2.7,对于字典的插入是乱序的,即插入 a,b,c,返回结果顺序可能是 a,c,b。

简单实践如下:

print("------------------------------初始化----------------------------------")

# 空字典
dict_empty = {}
# 输出 {} <class 'dict'>
print(dict_empty, type(dict_empty))
# 直接通过方法创建一个
dict_empty_1 = dict()
print(dict_empty_1)

# 键必须是唯一的,但值则不必。
# 如果key重复,则后面的会覆盖前面的
dict_0 = {"aa": "bb", "aa": "222"}
print(dict_0)
# 键必须是不可变的,如字符串,数字 , Boolean,此外,元组可以作为key,因为元组是不可变的,但是列表、集合、字典是可变的,都不能作为key
# 值可以取任何数据类型,可以是任何的 python 对象,既可以是标准的对象,也可以是用户定义的
dict_1 = {"aa": "bb", ("aaa", "bb"): "1212", True: 12}
print(dict_1)
# TypeError: unhashable type: 'list'
# dict_2 = {"aa":"bb",["aaa","bb"]:"1212"}
# print(dict_2)
# TypeError: unhashable type: 'set'
# dict_3 = {"aa":"bb",{"aaa","bb"}:"1212"}
# print(dict_3)
# TypeError: unhashable type: 'dict'
# dict_4 = {"aa":"bb",{"aaa":"aa","bb":"bb"}:"1212"}
# print(dict_4)
# value 可以是字符串,数字,列表,元组,集合,字典,并且可以继续嵌套下去
# 字典完美契合JSON的格式
dict_5 = {"aa": "bb", "bb": [12, 23, 14], "cc": (12, 23, 14), "dd": {12, 23, 14},
          "ee": {12: "aaa", 23: "bbb", 14: "ccc"}}
print(dict_5)

dict_now = {"aa": "a1", "bb": [11, 12, 13], "cc": (21, 22, 23), "dd": {31, 32, 33},
            "ee": {41: "e1", 42: "e2", 43: "e3"}}

# 创建一个新字典,以可迭代对象的所有值为key,然后指定一个初始化,如果不指定的话就为null
# 输出 {1: 99, 2: 99, 3: 99, 4: 99}
new_dict = dict.fromkeys([1, 2, 3, 4], 99)
print(new_dict)

print("------------------------------读取元素/子字典----------------------------------")
print("字典无法通过下标索引访问,只能通过key访问")

# 直接通过下标访问
print(dict_now["aa"])
print(dict_now["bb"][1:])
print(dict_now["ee"][42])
# 如果用字典里没有的键访问数据,会报错
# KeyError: 'ff'
# print(dict_now["ff"])

# 获取指定key的val,比通过下标访问好多了
a_val = dict_now.get("aa")
print(a_val)
# key不存在,返回 None,不报错
a_val_null = dict_now.get("aab")
print(a_val_null)
# 带默认值的get
ab_val = dict_now.get("aab", "111")
print(ab_val)

# 摘取特定的key组成一个子字典,
# 无法通过下标完成,但是可以通过字典推导式来完成
dict_key = ["aa", "bb", "cc"]
# 写法1
dict_child_1 = {key: value for key, value in dict_now.items() if key in dict_key}
print(dict_child_1)
# 写法2
dict_child_2 = {key: dict_now[key] for key in dict_now if key in dict_key}
print(dict_child_2)
# 写法3  dict_now.keys() & dict_key 这两个集合取并集
dict_child_3 = {key: dict_now[key] for key in dict_now.keys() & dict_key}
print(dict_child_3)

print("------------------------------字典元素的增删改查----------------------------------")

# 使用[] 可更新key对应的val,比 setdefault 好用多了
dict_now["ff"] = 12
print(dict_now)
# 如果key在字典中不存在,则直接添加 key和val,非常方便,比 setdefault 好用多了
dict_now["hh"] = 1111
print(dict_now)

# 如果key在字典中不存在,则插入这个key,你可以指定这个key的val,没指定的话,默认值就是None,最终返回这个key的val
# 如果key在字典中存在,则返回这个key的值,
# 所以这个方法实际上是不能更新指定key的val的,
# 要更新指定key的val,只能用update方法
ret_val = dict_now.setdefault("ff")
# 返回值为 None
print(ret_val)
ret_val_2 = dict_now.setdefault("gg", "g1")
# 返回值为 g1
print(ret_val_2)
# 返回值为 ee对应的val 为 {41: 'e1', 42: 'e2', 43: 'e3'}
ret_val_3 = dict_now.setdefault("ee", "aaa")
print(ret_val_3)
# 字典的 key为ee的val,并没有更新为 aaa,依然是 {41: 'e1', 42: 'e2', 43: 'e3'}
# 所以 setdefault 方法并不能用来更新 key 对应的 val
print(dict_now)

# update方法,有三种参数
# 第一种,直接传入一个字典,只有key在传入的字典中存在的val才会被更新
# 第二种,传入长度为2的可迭代对象的序列,比如[("a",1),("b",2)],第一项为key,第二项为val,跟第一种参数一样,只有key在传入参数中的val才会更新
# 第三种,直接传入关键字函数,name为字典的key,val为更新的目标值,
# 不能同时传入第一种和第二种参数,第一种/第二种参数 和 第三种参数可以同时生效,且第三种参数后生效,可以覆盖第一种/第二种参数
dict_copy = dict_now.copy()
dict_copy.update({"aa": 1, "bb": 2, "cc": 3})
print(dict_copy)
dict_copy = dict_now.copy()
dict_copy.update([("aa", 100), ("bb", 200), ("cc", 300)])
print(dict_copy)
dict_copy = dict_now.copy()
dict_copy.update(aa=98, bb=998, cc=9998)
print(dict_copy)
# 第一种参数不可以跟第三种参数一起生效
# dict_copy = dict_now.copy()
# dict_copy.update({"aa": 1, "bb": 2, "cc": 3}, [("aa", 100), ("bb", 200), ("cc", 300)])
# print(dict_copy)
# 第一种参数可以跟第三种参数一起生效
dict_copy = dict_now.copy()
dict_copy.update({"aa": "x", "bb": "y", "cc": "z"}, dd=998)
print(dict_copy)
# 第二种参数可以跟第三种参数一起生效
dict_copy = dict_now.copy()
dict_copy.update([("aa", 100), ("bb", 200), ("cc", 300)], dd=998)
print(dict_copy)
# aa 最终为998
dict_copy = dict_now.copy()
dict_copy.update({"aa": "x", "bb": "y", "cc": "z"}, aa=998)
print(dict_copy)

# 删除键 'Name' 不如 pop 方法好用
del dict_now['hh']
print(dict_now)
# 删除一个不存在的key,会报错
# 提示 KeyError: 'hhaa'
# del dict_now['hhaa']
# print(dict_now)

# 删除字典 key(键)所对应的值,返回被删除的值。如果key在字典中不存在,则报错,不过此时你可以指定一个默认值,这样key在字典中不存在就只会返回默认值,而不报错
# 当我们不知道key存不存在的时候,我们可以添加一个默认值,如果返回结果是默认值,则表示key不存在,如果返回结果不是默认值,则说明key存在,且已经删除成功
# 因为字典中存在 gg这个key,所以此时添加默认值也不会返回
val_1 = dict_now.pop("gg")
# 输出 g1
print(val_1)
# 因为 gg 这个key 已经被删除,所以再删一次,此时已经不存在这个key,会报错
# KeyError: 'hh'
# val_2 = dict_now.pop("gg")
# print(val_2)
# 添加默认值,表示key不存在的时候返回默认值
val_3 = dict_now.pop("gg", "aaa")
print(val_3)
print(dict_now)

# 返回并删除字典中的最后一对键和值。并将其作为一个两个元素的元组返回,如果字典为空,则报错
del_pair_tuple = dict_now.popitem()
print(del_pair_tuple)
print(dict_now)

print("------------------------------对字典的整体操作----------------------------------")
# 字典长度
print(len(dict_now))

# 将字典输出为字符串
print(str(dict_now))
# 和直接输出没啥区别
print(dict_now)

# 返回key的最大值和最小值
print(max(dict_now))
print(min(dict_now))

# 字典的复制
# 浅复制,不是深复制
# 如果key的val是对象或者字典,而对对象属性或者字典进行更新,是会同步到原字典中的
dict_copy = dict_now.copy()
print(dict_copy)
# 清空字典
dict_copy.clear()
print(dict_copy)

# 删除字典对象
# 删除之后对象都没了
del dict_copy
# 报错,并提示:name 'dict_copy' is not defined.
# print(dict_copy)


# 将所有的key,val转化为元组并列表,并封装为一个 dict_items 类型的变量,然后返回
# 一般在for循环中,想要直接获取key和val的话,会使用此函数
item_of_dict = dict_now.items()
# 内容为 dict_items([('aa', 'a1'), ('bb', [11, 12, 13]), ('cc', (21, 22, 23)), ('dd', {32, 33, 31}), ('ee', {41: 'e1', 42: 'e2', 43: 'e3'})])
# 类型为 dict_items
print(item_of_dict, type(item_of_dict))
# 将所有的key放到列表中,并封装为一个 dict_keys 类型的变量,然后返回
key_of_dict = dict_now.keys()
# 内容为 dict_keys(['aa', 'bb', 'cc', 'dd', 'ee'])
# 类型为 dict_keys
print(key_of_dict, type(key_of_dict))
# 将所有的val放到列表中,并封装为一个 dict_values 类型的变量,然后返回
val_of_dict = dict_now.values()
# 内容为 dict_values(['a1', [11, 12, 13], (21, 22, 23), {32, 33, 31}, {41: 'e1', 42: 'e2', 43: 'e3'}])
# 类型为 dict_values
print(val_of_dict, type(val_of_dict))

print("------------------------------字典元素的排序----------------------------------")


# 自定义排序规则
# 根据元素长度
def eleLen(elem):
    # 相当于一个hash操作
    # 返回值越大,升序排序的时候就越靠后
    if type(elem) == bool:
        return 1
    elif type(elem) == int:
        return len(str(elem))
    else:
        # 剩下的都是容器了
        return len(elem)


# 容器通用排序操作,返回一个新的列表,原字典是不变的,
# 主要是对字典的key进行排序,字典中的key的类型是不限定的,因此得定制key函数,否则无法比较,只能返回空列表
sorted_list = sorted(dict_now, key=eleLen, reverse=False)
print(dict_now)
print(sorted_list)

print("------------------------------对字典的符号操作,非常方便----------------------------------")
# 字典不支持 + 操作
# 字典不支持 * 操作

dict_new = {"aaa": 45, "bbb": 60}

# 直接通过 in 语句判断key是否在字典中
print("aaaa" in dict_new)
print("aaa" in dict_new)
# not in 判断元素是否不在字典中
print("aaa" not in dict_new)

# for-in 循环遍历list
for i in dict_new:
    print(i, dict_new[i], end=' ')
print()

# 这样很符合直觉
for k, v in dict_new.items():
    print(k, v, end=' ')
print()

print("------------------------------字典推导式----------------------------------")

# 前面的获取子字典的例子
# 写法1
dict_child_1 = {key: value for key, value in dict_now.items() if key in dict_key}
print(dict_child_1)
# 写法2
dict_child_2 = {key: dict_now[key] for key in dict_now if key in dict_key}
print(dict_child_2)
# 写法3  dict_now.keys() & dict_key 这两个集合取并集
dict_child_3 = {key: dict_now[key] for key in dict_now.keys() & dict_key}
print(dict_child_3)
# 将字典的所有的key加上一个后缀组成一个列表
dict_key_list = [key + "&&" for key in dict_now]
print(dict_key_list)

print("------------------------------ 字典的比较 ----------------------------------")

# 导入 operator 模块
import operator

dict_a = {1: 1, 2: 2}
dict_b = {1: 1, 2: 2}
dict_c = {1: 2, 2: 2}
print("operator.eq(a,b): ", operator.eq(dict_a, dict_b))
print("operator.eq(c,b): ", operator.eq(dict_a, dict_c))
# 复杂的比较就懒得比较了

print("------------------------------将别的容器对象转化为字典----------------------------------")
# 从列表转化而来
dict_from_list = dict.fromkeys([12, 23.45])
print(dict_from_list)
# 从字符串转化而来
dict_from_str = dict.fromkeys("abcdefg")
print(dict_from_str)
# 从元组转化而来
dict_from_tuple = dict.fromkeys((12, 23.45))
print(dict_from_tuple)
# 从集合转化而来
dict_from_set = dict.fromkeys({12, 23.45})
print(dict_from_set)

输出:

------------------------------初始化----------------------------------
{} <class 'dict'>
{}
{'aa': '222'}
{'aa': 'bb', ('aaa', 'bb'): '1212', True: 12}
{'aa': 'bb', 'bb': [12, 23, 14], 'cc': (12, 23, 14), 'dd': {12, 14, 23}, 'ee': {12: 'aaa', 23: 'bbb', 14: 'ccc'}}
{1: 99, 2: 99, 3: 99, 4: 99}
------------------------------读取元素/子字典----------------------------------
字典无法通过下标索引访问,只能通过key访问
a1
[12, 13]
e2
a1
None
111
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23)}
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23)}
{'bb': [11, 12, 13], 'aa': 'a1', 'cc': (21, 22, 23)}
------------------------------字典元素的增删改查----------------------------------
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12}
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111}
12
g1
{41: 'e1', 42: 'e2', 43: 'e3'}
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 1, 'bb': 2, 'cc': 3, 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 100, 'bb': 200, 'cc': 300, 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 98, 'bb': 998, 'cc': 9998, 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 'x', 'bb': 'y', 'cc': 'z', 'dd': 998, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 100, 'bb': 200, 'cc': 300, 'dd': 998, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 998, 'bb': 'y', 'cc': 'z', 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'hh': 1111, 'gg': 'g1'}
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12, 'gg': 'g1'}
g1
aaa
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}, 'ff': 12}
('ff', 12)
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}}
------------------------------对字典的整体操作----------------------------------
5
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}}
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}}
ee
aa
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}}
{}
dict_items([('aa', 'a1'), ('bb', [11, 12, 13]), ('cc', (21, 22, 23)), ('dd', {32, 33, 31}), ('ee', {41: 'e1', 42: 'e2', 43: 'e3'})]) <class 'dict_items'>
dict_keys(['aa', 'bb', 'cc', 'dd', 'ee']) <class 'dict_keys'>
dict_values(['a1', [11, 12, 13], (21, 22, 23), {32, 33, 31}, {41: 'e1', 42: 'e2', 43: 'e3'}]) <class 'dict_values'>
------------------------------字典元素的排序----------------------------------
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23), 'dd': {32, 33, 31}, 'ee': {41: 'e1', 42: 'e2', 43: 'e3'}}
['aa', 'bb', 'cc', 'dd', 'ee']
------------------------------对字典的符号操作,非常方便----------------------------------
False
True
False
aaa 45 bbb 60 
aaa 45 bbb 60 
------------------------------字典推导式----------------------------------
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23)}
{'aa': 'a1', 'bb': [11, 12, 13], 'cc': (21, 22, 23)}
{'bb': [11, 12, 13], 'aa': 'a1', 'cc': (21, 22, 23)}
['aa&&', 'bb&&', 'cc&&', 'dd&&', 'ee&&']
------------------------------ 字典的比较 ----------------------------------
operator.eq(a,b):  True
operator.eq(c,b):  False
------------------------------将别的容器对象转化为字典----------------------------------
{12: None, 23.45: None}
{'a': None, 'b': None, 'c': None, 'd': None, 'e': None, 'f': None, 'g': None}
{12: None, 23.45: None}
{12: None, 23.45: None}

Process finished with exit code 0

简单比较

异同点

数据容器可以从以下视角进行简单的分类:

列表 元组 字符串 集合 字典
元素数量 支持多个 支持多个 支持多个 支持多个 支持多个
元素类型 任意 任意 仅字符 任意 Key:Value Key:不可变类型的值 Value:任意类型
下标索引 支持 支持 支持 不支持 不支持
重复元素 支持 支持 支持 不支持 不支持
可修改性 支持 不支持 不支持 支持 支持
数据有序
使用场景 可修改、可重复的一批数据记录场景 不可修改、可重复的一批数据记录场景 一串字符的记录场景 不可重复的数据记录场景 以 Key 检索 Value 的数据记录场景

通用操作

这些通用操作在以上各小节中已经实践过,这里只是总结